package br.com.simora.relatorio;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;

import javax.annotation.PostConstruct;
import javax.inject.Inject;

import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperRunManager;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import br.com.caelum.vraptor.Controller;
import br.com.caelum.vraptor.Get;
import br.com.caelum.vraptor.Path;
import br.com.caelum.vraptor.Post;
import br.com.caelum.vraptor.Result;
import br.com.caelum.vraptor.observer.download.InputStreamDownload;
import br.com.caelum.vraptor.view.Results;
import br.com.simora.component.StringUteis;
import br.com.simora.controller.BasicController;
import br.com.simora.execucao.Execucao;
import br.com.simora.execucao.ExecucaoDAO;
import br.com.simora.execucao.ExecucaoVO;
import br.com.simora.musica.ArtistaDAO;
import br.com.simora.musica.Musica;
import br.com.simora.musica.MusicaDAO;
import br.com.simora.musica.MusicaVO;
import br.com.simora.radio.Radio;
import br.com.simora.radio.RadioDAO;

@Controller
public class RelatorioController extends BasicController {
	@Inject private ExecucaoDAO execucaoDAO;
	@Inject private RadioDAO radioDAO;
	@Inject private MusicaDAO musicaDAO;
	@Inject private ArtistaDAO artistaDAO;
	
	public RelatorioController(Result result, ResourceBundle bundle,
			ExecucaoDAO execucaoDAO, RadioDAO radioDAO, MusicaDAO musicaDAO,
			ArtistaDAO artistaDAO) {
    	this.result = result;
		this.bundle = bundle;
		this.execucaoDAO = execucaoDAO;
		this.radioDAO = radioDAO;
		this.musicaDAO = musicaDAO;
		this.artistaDAO = artistaDAO;
	}

    public RelatorioController(){}
    
	@PostConstruct
    public void init(){
        injetaUsuario();
    }
	
	@Path(value = "/" + RELATORIO)
    @Get
    public void relatorio() {}
   
    @Path(value = "/" + RELATORIO + "/" + RADIO)
    @Get
    public void radio() {
        result.include("listaRadios", execucaoDAO.recuperaTodos(Radio.class));
    }
    
    @Path(value = "/" + RELATORIO + "/" + PERIODO)
    @Get
    public void periodo() {
        result.include("listaRadios", execucaoDAO.recuperaTodos(Radio.class));
    }
    
    @Path(value = "/" + RELATORIO + "/" + ESTADO)
    @Get
    public void estado() {
        result.include("listaEstados", estados);
    }
    
    @Path(value = "/" + RELATORIO + "/recuperaCidades")
    @Post
    public void recuperaCidades(String estadoSigla) {
    	result.use(Results.json()).from(radioDAO.recuperaCidades(estadoSigla)).serialize();
    }
    
    @Path(value = "/" + RELATORIO + "/recuperaRadios")
    @Post
    public void recuperaRadios(String cidadeNome) {
    	result.use(Results.json()).from(radioDAO.recuperaRadioPorCidade(cidadeNome)).serialize();
    }
    
    @Path(value = "/" + RELATORIO + "/recuperaEstados")
    @Post
    public void recuperaEstados(String regiaoNome) {
    	result.use(Results.json()).from(radioDAO.recuperaEstados(regiaoNome)).serialize();
    }
    
    @Path(value = "/" + RELATORIO + "/recuperaMusicas")
    @Get
    public void recuperaMusicas(String query, String idArtista) {
    	result.use(Results.json()).from(musicaDAO.recuperaMusicaPorNomeEArtistaLike(query, idArtista)).serialize();
    }
    
    @Path(value = "/" + RELATORIO + "/recuperaArtistas")
    @Get
    public void recuperaArtistas(String query) {
    	result.use(Results.json()).from(artistaDAO.recuperaArtistaPorNomeLike(query)).serialize();
    }
    
    
    @Path(value = "/" + RELATORIO + "/geraPDF")
	@Post
	public InputStreamDownload geraPDF(Radio radio, Musica musica, Date dataInicio, Date dataFim, 
			String horaInicio, String horaFim, Boolean geraPdf, String tipoRelatorio){
        Map<String, Object> parametros = new HashMap<String, Object>();
        DateFormat df = new SimpleDateFormat("dd/MM/yyyy");

        parametros.put("dataInicio", df.format(dataInicio));
        parametros.put("dataFim", df.format(dataFim));

        List<Object> objs = new ArrayList<Object>();
        InputStream inputStream = null;
        String nomeRelatorio = "";
        if(radio.getId() == null || musica.getArtista().getId() == null){
        	if(StringUteis.isEmpty(tipoRelatorio) || "C".equals(tipoRelatorio)){
        		objs = recuperaExecucoes(radio, musica, dataInicio, dataFim, horaInicio, horaFim);
            	inputStream = getClass().getResourceAsStream("/relatorio/relatorioRadio.jasper");
            	nomeRelatorio = "relatorioCronologico.pdf";
        	} else {
	        	objs = recuperaMusicas(radio, musica, dataInicio, dataFim, horaInicio, horaFim);
	        	inputStream = getClass().getResourceAsStream("/relatorio/relatorioRanking.jasper");
	        	nomeRelatorio = "relatorioRanking.pdf";
        	}
        } else {
        	objs = recuperaExecucoes(radio, musica, dataInicio, dataFim, horaInicio, horaFim);
        	inputStream = getClass().getResourceAsStream("/relatorio/relatorioRadio.jasper");
        	nomeRelatorio = "relatorioCronologico.pdf";
        }
        
        try {
            byte[] bytes = JasperRunManager.runReportToPdf(inputStream, parametros, new JRBeanCollectionDataSource(objs));
            return new InputStreamDownload(new ByteArrayInputStream(bytes), "pdf", nomeRelatorio, true, bytes.length);
        } catch ( JRException exc ) {
            exc.printStackTrace();
        }
		return null;
	}
    
    private List<Object> recuperaExecucoes(Radio radio, Musica musica, Date dataInicio, Date dataFim, String horaInicio, String horaFim){
    	long HOUR = 3600*1000;
    	dataInicio.setTime(dataInicio.getTime());
    	dataFim.setTime(dataFim.getTime()+((24*HOUR)-1));
    	List<Object> objetos = new ArrayList<Object>();
    	List<Execucao> execs = execucaoDAO.recuperaExecucaoPorFiltro(radio, musica, dataInicio, dataFim, null, null);
    	
    	List<Execucao> execFim = new ArrayList<Execucao>();
    	if(musica != null && musica.getArtista() != null && null != musica.getArtista().getId()){
			for(Execucao e : execs){
				if(musica.getArtista().getId().intValue() == e.getMusica().getArtista().getId().intValue()){
					execFim.add(e);
				}
			}
		} else {
			execFim = execs;
		}
    	
    	if(execs != null && execs.size() > 0){
    		for (Execucao exec : execFim){
				ExecucaoVO vo = new ExecucaoVO();
    			vo.setDataHora(exec.getDataHora());
    			vo.setMusica(exec.getMusica());
    			vo.setArtistaNome(exec.getMusica().getArtista().getNome());
    			vo.setMusicaNome(exec.getMusica().getNome());
    			vo.setNomeRadio(exec.getRadio().getNome());
    			vo.setRadio(exec.getRadio());
    			objetos.add(vo);
    		}
    	}
    	return objetos;
    }
    
    private List<Object> recuperaMusicas(Radio radio, Musica musica, Date dataInicio, Date dataFim, String horaInicio, String horaFim){
    	long HOUR = 3600*1000;
    	dataInicio.setTime(dataInicio.getTime());
    	dataFim.setTime(dataFim.getTime()+((24*HOUR)-1));
    	List<Object> objetos = new ArrayList<Object>();
		List<Musica> execsT = execucaoDAO.recuperaMusicasMaisTocadasFiltro(musica, dataInicio, dataFim, radio, null, null);
		if(execsT != null && execsT.size() > 0){
    		for (Musica exec : execsT){
    			MusicaVO vo = new MusicaVO();
    			vo.setNomeArtista(exec.getArtista().getNome());
    			vo.setNomeMusica(exec.getNome());
    			vo.setTotal(exec.getTotal());
    			objetos.add(vo);
    		}
    	}
    	return objetos;
    }
    
    @Path(value = "/" + RELATORIO + "/" + GERAR)
    @Post
    public void gerar(Radio radio, Musica musica, Date dataInicio, Date dataFim, 
    		String horaInicio, String horaFim, Integer quantidadeRegistros, Integer pagina, String tipoRelatorio) {
    	result.include("dataInicio", dataInicio);
    	result.include("dataFim", dataFim);
    	result.include("radio", radio);
    	long HOUR = 3600*1000;
    	dataInicio.setTime(dataInicio.getTime());
    	dataFim.setTime(dataFim.getTime()+((24*HOUR)-1));
    	if(radio.getId() == null || musica.getArtista().getId() == null){
    		if(!StringUteis.isEmpty(tipoRelatorio) && "C".equals(tipoRelatorio)){
    			List<Execucao> execsT = execucaoDAO.recuperaExecucaoPorFiltro(radio, musica, dataInicio, dataFim, null, null);
        		List<Execucao> execFim = new ArrayList<Execucao>();
        		if(musica != null && musica.getArtista() != null && null != musica.getArtista().getId()){
        			for(Execucao e : execsT){
        				if(musica.getArtista().getId().intValue() == e.getMusica().getArtista().getId().intValue()){
        					execFim.add(e);
        				}
        			}
        		} else {
        			execFim = execsT;
        		}
        		Integer tamanho = execFim.size();
        		if(tamanho > quantidadeRegistros){
        			if(pagina > 1){
        				Integer inicio = (pagina-1) * quantidadeRegistros;
        				Integer fim = inicio + quantidadeRegistros;
        				if(fim > tamanho){
        					execFim = execFim.subList(inicio, tamanho);
        				} else {
        					execFim = execFim.subList(inicio, fim);
        				}
        			} else {
        				execFim = execFim.subList(0, 49);
        			}
        		}
        		result.include("listaExecucoes", execFim);
        		result.include("totalRegistros", tamanho);
        		result.include("pagina", pagina);
        		Integer totalPaginas =  ( execsT.size() + (quantidadeRegistros - 1) ) / quantidadeRegistros;  
            	result.include("totalPaginas", totalPaginas);
        		result.include("radio", radio);
        		result.include("tipoRelatorio", tipoRelatorio);
        		result.include("musica", musica);
        		result.include("quantidadeRegistros", quantidadeRegistros);
        		result.redirectTo(RelatorioController.class).relatorio();
    		} else {
	    		List<Musica> execsTotal = execucaoDAO.recuperaMusicasMaisTocadasFiltro(musica, dataInicio, dataFim, radio, null, null);
	    		List<Musica> execs = execucaoDAO.recuperaMusicasMaisTocadasFiltro(musica, dataInicio, dataFim, radio, quantidadeRegistros, pagina);
	    		
	    		result.include("listaMusicas", execs);
	    		result.include("totalRegistros", execsTotal.size());
	    		result.include("pagina", pagina);
	    		Integer totalPaginas =  ( execsTotal.size() + (quantidadeRegistros - 1) ) / quantidadeRegistros;  
	        	result.include("totalPaginas", totalPaginas);
	    		result.include("radio", radio);
	    		result.include("musica", musica);
	    		result.include("tipoRelatorio", tipoRelatorio);
	    		result.include("quantidadeRegistros", quantidadeRegistros);
	    		result.redirectTo(RelatorioController.class).relatorio();
    		}
    	} else {
    		radio = (Radio) execucaoDAO.find(Radio.class, radio.getId());
			List<Execucao> execsT = execucaoDAO.recuperaExecucaoPorFiltro(radio, musica, dataInicio, dataFim, null, null);
    		List<Execucao> execFim = new ArrayList<Execucao>();
    		if(musica != null && musica.getArtista() != null && null != musica.getArtista().getId()){
    			for(Execucao e : execsT){
    				if(musica.getArtista().getId().intValue() == e.getMusica().getArtista().getId().intValue()){
    					execFim.add(e);
    				}
    			}
    		} else {
    			execFim = execsT;
    		}
    		Integer tamanho = execFim.size();
    		if(tamanho > quantidadeRegistros){
    			if(pagina > 1){
    				Integer inicio = (pagina-1) * quantidadeRegistros;
    				Integer fim = inicio + quantidadeRegistros;
    				if(fim > tamanho){
    					execFim = execFim.subList(inicio, tamanho);
    				} else {
    					execFim = execFim.subList(inicio, fim);
    				}
    			} else {
    				execFim = execFim.subList(0, 49);
    			}
    		}
    		result.include("listaExecucoes", execFim);
    		result.include("totalRegistros", tamanho);
    		result.include("pagina", pagina);
    		Integer totalPaginas =  ( execsT.size() + (quantidadeRegistros - 1) ) / quantidadeRegistros;  
        	result.include("totalPaginas", totalPaginas);
    		result.include("radio", radio);
    		
    		result.include("musica", musica);
    		result.include("quantidadeRegistros", quantidadeRegistros);
    		result.redirectTo(RelatorioController.class).relatorio();
    	}
    }
	
	@Override
	protected void redirect() {}

}